package be.rhok.eenzaamheidswijzer.filter;

import be.rhok.eenzaamheidswijzer.filter.util.HttpServletResponseContentWrapper;
import org.apache.commons.lang.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * {@link javax.servlet.Filter} for JSONP requests.
 */
public class JsonpFilter implements Filter {

    public static final String CALLBACK_FUNCTION_INIT_PARAM = "callback-function";

    public static final String DEFAULT_CALLBACK_FUNCTION_PARAMETER = "callback";

    private String callbackFunctionParameterName = DEFAULT_CALLBACK_FUNCTION_PARAMETER;

    public void doFilter(final ServletRequest req, final ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        if (resp instanceof HttpServletResponse && isJsonpRequest(req)) {
            JsonpHttpServletResponseWrapper wrapper = new JsonpHttpServletResponseWrapper((HttpServletResponse) resp, getCallbackFunction(req));

            //wrapper.setCharacterEncoding("UTF-8");
            chain.doFilter(req, wrapper);
            wrapper.flushWrapper();
        } else {
            chain.doFilter(req, resp);
        }
    }

    private boolean isJsonpRequest(ServletRequest req) {
        return StringUtils.isNotEmpty(getCallbackFunction(req));
    }

    private String getCallbackFunction(ServletRequest req) {
        if (req.getParameterMap().containsKey(callbackFunctionParameterName)) {
            return ((String[]) req.getParameterMap().get(callbackFunctionParameterName))[0];
        }

        return null;
    }

    public void init(FilterConfig config) throws ServletException {
        String callbackFunctionParam = config.getInitParameter(CALLBACK_FUNCTION_INIT_PARAM);
        if (callbackFunctionParam != null && !callbackFunctionParam.equals("")) {
            this.callbackFunctionParameterName = callbackFunctionParam;
        }
    }

    public String getCallbackFunctionParameterName() {
        return callbackFunctionParameterName;
    }

    public void setCallbackFunctionParameterName(String callbackFunctionParameterName) {
        this.callbackFunctionParameterName = callbackFunctionParameterName;
    }

    public void destroy() {
    }

    private class JsonpHttpServletResponseWrapper extends HttpServletResponseContentWrapper {

        private final String callback;

        private JsonpHttpServletResponseWrapper(HttpServletResponse response, String callback) {
            super(response);
            this.callback = callback;
        }

        @Override
        public byte[] wrap(byte[] content) throws UnsupportedEncodingException {
            String contentStr = new String(content, getCharacterEncoding());
            return (callback + "(" + contentStr + ");").getBytes(getCharacterEncoding());
        }
    }
}